﻿package cont;


import core.*;
import mess.*;
import scrn.*;


// ======================================================= Список всех контактов


public final class ContMan {

// ======================================================= Глобальные переменные
public boolean fContCh = true; // Список контактов претерпел изменения

// Контакты
public int selType = Cont.UNK; // Тип активного контакта в списке sort
public int selNum = -1; // Номер активного контакта в массиве его типа

// Комнаты
public ContRoom room[] = new ContRoom[Setting.MAX_ROOM]; // Контакты комнат
private int roomTot = 0; // Общее кол-во комнат

// Персональные
public ContOne one[] = new ContOne[Setting.MAX_ONE]; // Персональные контакты
private int oneTot = 0; // Общее кол-во контактов

// Кэш ников
public String cache[] = new String[Setting.MAX_CACHE]; // Кэш ников

// Другое
private int newNum = 0; // Общее кол-во новых сообщений у всех контактов


// =============================================================== Инициализация
public ContMan() {

	Mess.m("ContMan.init", "=====");
}


// ====================================================== Персональное сообщение
public void addTextOne(int contNum, MessOne messOne) {

	if ((oneTot > contNum) && (contNum >= 0)) {
		if (one[contNum] != null) {
			synchronized (Man.main) {
				one[contNum].addMess(messOne);
				if (!isSel(Cont.ONE, contNum)) {
					// Установить флаг нового сообщения
					if (!one[contNum].fNew) {
						one[contNum].fNew = true;
						newNum++;
					}
				}
			}
		} else {
			Mess.m("ContMan.addTextOne", "Сообщение от неизвестного адресата №="
					+ contNum);
		}
	}
}


// ========================================================= Сообщение в комнату
public void addTextRoom(int roomNum, MessRoom messRoom) {

	// Заполняем поля ников
	switch (messRoom.fromType) {
		case MessRoom.FROM_ONE:
			messRoom.fromCache = one[messRoom.fromNum].name;
			break;
		case MessRoom.FROM_CACHE_OLD:
			messRoom.fromCache = cache[messRoom.fromNum];
			break;
	}

	switch (messRoom.tarType) {
		case MessRoom.TAR_ONE:
			messRoom.tarCache = one[messRoom.tarNum].name;
			break;
		case MessRoom.TAR_CACHE_OLD:
			messRoom.tarCache = cache[messRoom.tarNum];
			break;
	}

	//	Mess.m("ContMan.addTextRoom", "before sync 1");
	synchronized (Man.main) {
		//		Mess.m("ContMan.addTextRoom", "after sync 1");
		room[roomNum].addMess(messRoom);

		if (!isSel(Cont.ROOM, roomNum)) {
			if (!room[roomNum].fNew) {
				room[roomNum].fNew = true;
				newNum++;
			}
		}
	}
	//	Mess.m("ContMan.addTextRoom", "out sync 1");

}


// =========================================================== Удаление контакта
public String delCont(int contType, int contNum) {

	Cont cont = getCont(contType, contNum);
	if (cont.fNew) {
		newNum--;
	}

	switch (contType) {
		case Cont.ONE:
			oneTot--;
			one[contNum] = one[oneTot];
			one[oneTot] = null;
			break;
		case Cont.ROOM:
			roomTot--;
			room[contNum] = room[roomTot];
			room[roomTot] = null;
			break;
		default:
			Mess.m("ContMan.contDel", "Неизвестный тип контакта: " + contType);
	}

	if (isSel(contType, contNum)) {
		selPrev();
	}

	fContCh = true;
	return cont.name;

}


// =============================================== Добавление кешированного ника
public void addCache(int num, String name) {

	cache[num] = name;
}


// ========================================================= Добавление контакта
public int addCont(int contType, Cont cont, int mode) {

	int newNum = -1;
	switch (contType) {
		case Cont.ONE:
			if (oneTot < Setting.MAX_ONE) {
				synchronized (Man.main) {
					one[oneTot] = (ContOne) cont;
					newNum = oneTot;
					oneTot++;
				}
			}
			break;
		case Cont.ROOM:
			if (roomTot < Setting.MAX_ROOM) {
				synchronized (Man.main) {
					ContRoom r = (ContRoom) cont;
					r.info.statNum = RoomInfo.ONLINE;
					r.titText = r.name + " - " + r.info.oneTot + " в сети";
					newNum = roomTot;
					room[roomTot] = r;
					roomTot++;
				}
			}
			break;
		default:
			Mess.err("ContMan.addCont",
					"Попытка добавить контакт неизвестного типа. Тип=" + contType);
	}

	if (newNum >= 0) {
		this.selCont(contType, newNum);
	}

	fContCh = true;

	return newNum;
}


// ========================================================= Очистить все списки
public void clearAll() {

	clearList(Cont.ONE);
	clearList(Cont.ROOM);
	newNum = 0;

}


// ============================================================= Очистить список
public void clearList(int contType) {

	switch (contType) {
		case Cont.ONE:
			synchronized (Man.main) {
				for (int q = oneTot - 1; q >= 0; --q) {
					if (one[q].fNew) {
						newNum--;
					}
					one[q] = null;
				}
				oneTot = 0;
			}
			break;
		case Cont.ROOM:
			synchronized (Man.main) {
				for (int q = roomTot - 1; q >= 0; --q) {
					if (room[q].fNew) {
						newNum--;
					}
					room[q] = null;
				}
				roomTot = 0;
			}
			break;
		default:
			Mess.err("ContMan.clearList", "Неизвестный тип контакта: " + contType);
	}

	fContCh = true;
}


// =================================================== Загрузка контактов из RMS
public void listLoad() {

	// TODO Реализовать метод
}


// ================================================== Сохранение контактов в RMS
public void listSave() {

	// TODO Реализовать метод
}


// ============================================================= Вернуть контакт
public Cont getCont(int contType, int contNum) {

	switch (contType) {
		case Cont.ONE:
			return one[contNum];
		case Cont.ROOM:
			return room[contNum];
		default:
			return null;
	}

}


// ========================================== Вернуть общее количество контактов
public int getContNum() {

	return oneTot + roomTot;
}


// ================================================================== Выдать CRC
public int getCRC(int contType) {

	Mat.crcReset();

	switch (contType) {
		case Cont.ONE:
			for (int q = 0; q < oneTot; ++q) {
				Mat.crcUpdate(Mat.utf2iso(one[q].name));
			}
			break;
		case Cont.ROOM:
			for (int q = 0; q < roomTot; ++q) {
				Mat.crcUpdate(Mat.utf2iso(room[q].name));
			}
			break;
		default:
			Mess.err("ContMan.getCRC", "Неизвестный тип контакта - " + contType);
	}

	return Mat.getCrc();
}


// ===================================================== Выдать кол-во контактов
public int getTot(int contType) {

	switch (contType) {
		case Cont.ONE:
			return oneTot;
		case Cont.ROOM:
			return roomTot;
		default:
			Mess.err("ContMan.getFreeSlot", "Неизвестный тип контакта - " + contType);
	}

	return -1;
}


//===================================================== Статус комнаты изменился
public String inStatRoom(int roomNum, byte[] buf) {

	String statText = "-";

	try {
		ContRoom r = room[roomNum];
		r.fromByte(buf);
		r.titText = r.name + " - " + r.info.oneTot + " в сети";
		statText = room[roomNum].info.mess;
	} catch (Exception e) {
		Mess.err("ContMan.inStatRoom", "Ошибка установки статуса. Комната №"
				+ roomNum + ", всего " + roomTot, e);
	}

	return statText;
}


// ==================================================== Индекс текущего контакта
public int getSelNum() {

	return selNum;
}


// ==================================================== Вернуть активный контакт
public Cont getSelCont() {

	return getCont(selType, selNum);
}


// ================================================== Ник персонального контакта
public String getFrom(int contNum, int maxLen) {

	// maxLen - максимальная возвращаемая длина. 0 - весь ник
	String name = one[contNum].name;
	if (maxLen > 0) {
		name = name.substring(0, Math.min(maxLen, name.length()));
	}

	return name;
}


// =========================================== Количество новых сообщений в фоне
public int getNewState() {

	return newNum;
}


// ==================================================== Номер активного контакта
//public int getNum() {
//
//	return 
//}


// ================================================================ Тип контакта
//public int getType(int index) {
//
//	if ((index >= 0) & (index < sort.size())) {
//		return ((ContSort) sort.elementAt(index)).type;
//	} else {
//		return Cont.UNK;
//	}
//}


// ====================================================== Тип активного контакта
public int getSelType() {

	return selType;
}


// ====================================================== Подтверждение доставки
public void inResOne(int contNum, int messNum) {

	one[contNum].setMessColor(messNum, OneCol.T_OUT_ADR);
}


public void inResRoom(int roomNum, int messNum) {

	room[roomNum].setMessColor(messNum, RoomCol.T_OUT_ADR);
}


// =============================================== Проверяет, выделен ли контакт
public boolean isSel(int contType, int contNum) {

	if ((selType == contType) && (selNum == contNum)) {
		return true;
	} else {
		return false;
	}
}


// ========================================================================= Кто
// Возвращает имя запрошенного контакта
public String getContName(int contType, int contNum) {

	switch (contType) {
		case Cont.ONE:
			return one[contNum].name;
		case Cont.ROOM:
			return room[contNum].name;
		default:
			Mess.err("ContMan.contName", "Неизвестный тип контакта:" + contType);
			return null;
	}

}


// ============================================================= Выбрать контакт
public void selCont(int contType, int contNum) {

	selType = contType;
	selNum = contNum;
}


// =================================================== Выбрать следующий контакт
public void selNext() {

	boolean fRun = true;

	while (fRun) { // Цикл перебора по всем типам контактов

		while (fRun && (selType == Cont.ONE)) { // Цикл перебора по перс. контактам
			while (fRun && (++selNum < oneTot)) {
				if ((newNum <= 0) || (one[selNum].fNew)) { // Найден конт. с новым сообщением ИЛИ новых нет. Стоп.
					fRun = false;
					if (newNum > 0) {
						newNum--;
						one[selNum].fNew = false;
					}
				} // Этот контакт - не с новым И новые есть. Ищем дальше
			}

			if (fRun) { // Продолжать поиск в следующей группе
				selType = Cont.ROOM;
				selNum = -1;
			}

		}

		while (fRun && (selType == Cont.ROOM)) { // Цикл перебора по комнатам
			while (fRun && (++selNum < roomTot)) {
				if ((newNum <= 0) || (room[selNum].fNew)) { // Найден конт. с новым сообщением ИЛИ новых нет. Стоп.
					fRun = false;
					if (newNum > 0) {
						newNum--;
						room[selNum].fNew = false;
					}
				} // Этот контакт - не с новым И новые есть. Ищем дальше
			}

			if (fRun) { // Продолжать поиск в следующей группе
				selType = Cont.ONE;
				selNum = -1;
			}

		}

	}
}


// ================================================== Выбрать предыдущий контакт
public void selPrev() {

	boolean fRun = true;

	while (fRun) { // Цикл перебора по всем типам контактов

		while (fRun && (selType == Cont.ONE)) { // Цикл перебора по перс. контактам
			while (fRun && (--selNum >= 0)) {
				if ((newNum <= 0) || (one[selNum].fNew)) { // Найден конт. с новым сообщением ИЛИ новых нет. Стоп.
					fRun = false;
					if (newNum > 0) {
						newNum--;
						one[selNum].fNew = false;
					}
				} // Этот контакт - не с новым И новые есть. Ищем дальше
			}

			if (fRun) { // Продолжать поиск в следующей группе
				selType = Cont.ROOM;
				selNum = roomTot;
			}

		}

		while (fRun && (selType == Cont.ROOM)) { // Цикл перебора по комнатам
			while (fRun && (--selNum >= 0)) {
				if ((newNum <= 0) || (room[selNum].fNew)) { // Найден конт. с новым сообщением ИЛИ новых нет. Стоп.
					fRun = false;
					if (newNum > 0) {
						newNum--;
						room[selNum].fNew = false;
					}
				} // Этот контакт - не с новым И новые есть. Ищем дальше
			}

			if (fRun) { // Продолжать поиск в следующей группе
				selType = Cont.ONE;
				selNum = oneTot;
			}

		}

	}
}


// ===================================================== Задать список контактов
public void setList(int contType, Cont[] conts) {

	clearList(contType);

	switch (contType) {
		case Cont.ONE:
			for (int q = 0; q < conts.length; ++q) {
				ContOne[] ones = (ContOne[]) conts;
				addCont(Cont.ONE, ones[q], Cont.M_IO);
			}
			break;
		case Cont.ROOM:
			for (int q = 0; q < conts.length; ++q) {
				ContRoom[] rooms = (ContRoom[]) conts;
				addCont(Cont.ROOM, rooms[q], Cont.M_IO);
			}
			break;
		default:
			Mess.err("ContMan.setList", "Неизвестный тип контакта:" + contType);
	}

	// selCont(contType, info.length - 1); // ### Правильно селектировать контакты
	// после загрузки

	fContCh = true;

}


// ================================================ Задать режим работы контакта
public void setMode(int contType, int slotNum, int mode) {

	switch (contType) {
		case Cont.ONE:
			break;
		case Cont.ROOM:
			Mess.m("ContMan.unblock", "Функция не определена. contType=" + contType);
			break;
		default:
			Mess.err("ContMan.unblock", "Неизвестный тип контакта: " + contType);
	}
}


// =============================================================== Задать статус
public void setStat(StatOne statOne) {

	if ((statOne.fromNum >= 0) && (statOne.fromNum < oneTot)) { // Контакт существует
		one[statOne.fromNum].info.statNum = statOne.statNum;
	} else { //
		Mess.err("ContMan.setStat", "Контакта №" + statOne.fromNum
				+ " нет в списке");
	}
}


// ============================================================== Состояние сети
public void fOnline(boolean fOnline) {

	if (!fOnline) {
		int q;
		for (q = oneTot - 1; q >= 0; --q) {
			one[q].info.statNum = StatOne.OFFLINE;
		}

		for (q = roomTot - 1; q >= 0; --q) {
			room[q].info.statNum = RoomInfo.OFFLINE;
			room[q].titText = room[q].name;
		}
	}
}


// ======================================================================= Выход
public void exit() {

}

}
